#include <iostream>
#include <stdio.h>
#include <memory>

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>
#include <wait.h>

union semun
{
    /* data */
    int val;
    struct semid_ds *buf;
    unsigned short *array;
    struct seminfo *_buf;
};


#define ERR_EXIT(m) \
    do\
    {\
        perror(m);\
        exit(EXIT_FAILURE);\
    }while(0) 

int sem_create(key_t key)
{
    int sem_id;
    sem_id = semget(key, 1, IPC_CREAT|IPC_EXCL|0666);
    if(sem_id == -1)
        ERR_EXIT("semget");
    return sem_id;
}

int sem_open(key_t key)
{
    int sem_id;
    sem_id = semget(key, 0, 0);
    if(sem_id == -1)
        ERR_EXIT("semget");
    return sem_id;
}

int sem_setval(int semid, int val)
{
    union semun su;
    su.val = val;
    int ret = semctl(semid, 0, SETVAL, su);
    if(ret == -1)
        ERR_EXIT("semctl");

    return 0;
}


int sem_getval(int semid)
{

    int ret = semctl(semid, 0, GETVAL, 0);
    if(ret == -1)
        ERR_EXIT("semctl");

    return ret;
}

int sem_d(int semid)
{
    int ret;
    ret = semctl(semid, 0 ,IPC_RMID,0);
    if(ret == -1)
        ERR_EXIT("semctl");
    return 0;
}
int sem_p(int semid)
{
    struct sembuf sb = {0, -1, 0};
    int ret = semop(semid, &sb, 1);
    if(ret == -1)
        ERR_EXIT("semop");
    
    return ret;
}

int sem_v(int semid)
{
    struct sembuf sb = {0, 1, 0};
    int ret = semop(semid, &sb, 1);
    if(ret == -1)
        ERR_EXIT("semop");
    
    return ret;
}
int semid;

void print(char op_char)
{
    int pause_time;
    srand(getpid());
    int i;
    for(i = 0; i < 10; i++){
        sem_p(semid);
        printf("\n%c",op_char);
        fflush(stdout);
        pause_time = rand()%3;
        sleep(pause_time);
        printf("%c %d",op_char,getpid());
        fflush(stdout);
        sem_v(semid);
        pause_time = rand()%2;
        sleep(pause_time);
    }
}
int main(int argv, char**argc)
{
    printf("************  sem!!!   **************\n");
    /* add test code! */

    semid = sem_create(IPC_PRIVATE);
    sem_setval(semid, 0);
    pid_t pid;
    pid = fork();
    if(pid == -1)
        ERR_EXIT("fork");

    if(pid > 0){
        sem_setval(semid,1);
        print('o');
        wait(NULL);
        sem_d(semid);
    }else {
        print('x');
    }
    
    
    return 0;
}



